package com.quectel.core.module.workorder.service.impl;

import com.quectel.constant.OrderCodePrefixConstants;
import com.quectel.constant.core.alarm.AlarmConstants;
import com.quectel.constant.core.workorder.WorkOrderConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.util.aspect.lock.annotation.Lock;
import com.quectel.core.constants.RedisLockConstants;
import com.quectel.core.module.alarm.dto.AlarmEventRecordDto;
import com.quectel.core.module.alarm.service.AlarmEventRecordService;
import com.quectel.core.module.village.dto.VillageBuildingDto;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.dto.VillageFloorDto;
import com.quectel.core.module.village.dto.VillageRoomDto;
import com.quectel.core.module.village.service.VillageBuildingService;
import com.quectel.core.module.village.service.VillageFloorService;
import com.quectel.core.module.village.service.VillageRoomService;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.core.module.workorder.dao.WorkOrderDao;
import com.quectel.core.module.workorder.dto.WorkOrderChargeDto;
import com.quectel.core.module.workorder.dto.WorkOrderDirectDto;
import com.quectel.core.module.workorder.dto.WorkOrderDto;
import com.quectel.core.module.workorder.dto.WorkOrderLogDto;
import com.quectel.core.module.workorder.dto.datav.WorkOrderCountDto;
import com.quectel.core.module.workorder.entity.WorkOrderEntity;
import com.quectel.core.module.workorder.service.WorkOrderChargeService;
import com.quectel.core.module.workorder.service.WorkOrderDirectService;
import com.quectel.core.module.workorder.service.WorkOrderLogService;
import com.quectel.core.module.workorder.service.WorkOrderService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.DateUtils;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.kit.OrderUtils;
import com.quectel.util.kit.Snowflake;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 * @date 2021-10-19 13:06:54
 */
@DubboService
public class WorkOrderServiceImpl implements WorkOrderService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WorkOrderServiceImpl.class);

    @Autowired
    private WorkOrderDao workOrderDao;
    @Autowired
    private WorkOrderLogService workOrderLogService;
    @Autowired
    private VillageService villageService;
    @Autowired
    private AlarmEventRecordService alarmEventRecordService;
    @Autowired
    private WorkOrderDirectService workOrderDirectService;
    @Autowired
    private WorkOrderChargeService workOrderChargeService;
    @Autowired
    private VillageBuildingService villageBuildingService;
    @Autowired
    private VillageFloorService villageFloorService;
    @Autowired
    private VillageRoomService villageRoomService;

    @Override
    public WorkOrderCountDto countWorkOrder(Map<String, Object> params) {
        long millis = System.currentTimeMillis();

        WorkOrderCountDto workOrderCountDto = new WorkOrderCountDto();

        params.put("endTime", DateUtils.getCurrentDateStr(DateUtils.FormatType.COMMON));


        params.put("startTime", DateUtils.getCurrentDateStr(DateUtils.FormatType.SIMPLE) + " 00:00:00");
        //本日
        workOrderCountDto.setTodayTotal(workOrderDao.queryTotal(params));

        //计算今天星期几
        int weekNum = DateUtils.getWeekNum(new Date(millis));
        params.put("startTime", DateUtils.format(new Date(millis - (weekNum - 1) * 24L * 60 * 60 * 1000),
                DateUtils.FormatType.SIMPLE) + " 00:00:00");
        //本周
        workOrderCountDto.setWeekTotal(workOrderDao.queryTotal(params));

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(millis));
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        params.put("startTime", DateUtils.format(calendar.getTime(),
                DateUtils.FormatType.SIMPLE) + " 00:00:00");
        //本月
        workOrderCountDto.setMonthTotal(workOrderDao.queryTotal(params));

        //工单总数
        params.remove("startTime");
        params.remove("endTime");
        workOrderCountDto.setTotal(workOrderDao.queryTotal(params));

        //工单完成数
        params.put("status", WorkOrderConstants.ORDER_STATUS_FINISHED);
        workOrderCountDto.setCompleteCount(workOrderDao.queryTotal(params));

        //工单未完成数
        workOrderCountDto.setIncompleteCount(workOrderCountDto.getTotal() - workOrderCountDto.getCompleteCount());


        return workOrderCountDto;
    }

    @Override
    @Lock(
            lockExpresses = {
                    RedisLockConstants.WORK_ORDER_LOG_SEQ_INC_LOCK + "#{#workOrderDto.id}"
            }
    )
    @Transactional
    public Long saveOrUpdateWorkOrderAndLog(WorkOrderDto workOrderDto) {
        final Date currentDate = new Date();

        if (workOrderDto.getId() == null) {
            //指派的有人
            workOrderDto.setOrderCode(OrderUtils.getOrderNo(OrderCodePrefixConstants.WORK_ORDER_PREFIX));

            // 初始化工单存在定向配置
            if (Objects.isNull(workOrderDto.getHandlerId()) && WorkOrderConstants.ORDER_STATUS_INIT.equals(workOrderDto.getStatus())) {
                WorkOrderDirectDto workOrderDirectDto = workOrderDirectService.selectOne(workOrderDto.getVillageId(), workOrderDto.getCategory(), workOrderDto.getType());
                if (Objects.nonNull(workOrderDirectDto) && SystemConstants.ENABLE.equals(workOrderDirectDto.getStatus())) {
                    // 存在定向配置，并且可用，处理人直接接单
                    workOrderDto.setHandlerId(workOrderDirectDto.getDeptPersonId());
                    workOrderDto.setStatus(WorkOrderConstants.ORDER_STATUS_HANDLING);
                    workOrderDto.setFirstHandTime(workOrderDto.getCreateTime());

                    // 添加工单派发日志
                    List<WorkOrderLogDto> baseLogList = workOrderDto.getWorkOrderLogDtoList();
                    WorkOrderLogDto initLog = new WorkOrderLogDto();
                    initLog.setHandlerId(workOrderDto.getHandlerId());
                    initLog.setHandlerType(WorkOrderConstants.ORDER_HANDLER_TYPE_DEPT_PERSON);
                    initLog.setOrderStatus(WorkOrderConstants.ORDER_STATUS_HANDLING);
                    initLog.setOrderDes("根据工单定向配置自动派发:" + (Objects.nonNull(workOrderDirectDto.getDeptPerson())
                            ? workOrderDirectDto.getDeptPerson().getName() : String.format("员工(%s)", workOrderDirectDto.getDeptPersonId())) + " 处理工单");
                    initLog.setCreateTime(workOrderDto.getCreateTime());
                    if (CollectionUtils.isEmpty(baseLogList)) {
                        workOrderDto.setWorkOrderLogDtoList(Collections.singletonList(initLog));
                    } else {
                        baseLogList.add(initLog);
                    }
                }
            }

            Long id = save(workOrderDto);
            workOrderDto.setId(id);
        } else {
            updateById(workOrderDto);
        }
        if (workOrderDto.getWorkOrderLogDtoList() != null) {
            List<WorkOrderLogDto> workOrderLogDtoList = workOrderDto.getWorkOrderLogDtoList();
            workOrderLogDtoList.forEach(v -> {
                v.setWorkOrderId(workOrderDto.getId());
                workOrderLogService.save(v);
            });
        }

        if (CollectionUtils.isNotEmpty(workOrderDto.getWorkOrderServiceItems())) {
            List<WorkOrderChargeDto> workOrderChargeDtos = workOrderDto.getWorkOrderServiceItems().parallelStream().map(o -> {
                WorkOrderChargeDto workOrderChargeDto = new WorkOrderChargeDto();
                workOrderChargeDto.setWorkOrderId(workOrderDto.getId());
                workOrderChargeDto.setWorkOrderServiceItemId(o.getId());
                workOrderChargeDto.setWorkOrderServiceItemJson(JacksonUtils.toJsonString(o));
                workOrderChargeDto.setAmount(o.getAmount());
                workOrderChargeDto.setCreateTime(currentDate);
                return workOrderChargeDto;
            }).collect(Collectors.toList());
            workOrderChargeService.saveBatch(workOrderChargeDtos);
        }

        if (WorkOrderConstants.ORDER_SOURCE_ALARM.equals(workOrderDto.getOrderSource())) {
            if (WorkOrderConstants.ORDER_STATUS_FINISHED.equals(workOrderDto.getStatus())) {
                //告警触发的工单被关闭 事件也要跟随关闭
                if (workOrderDto.getSourceId() != null && workOrderDto.getSourceId() > 0) {
                    AlarmEventRecordDto alarmEventRecordDto = alarmEventRecordService.selectById(workOrderDto.getSourceId());
                    alarmEventRecordDto.setStatus(AlarmConstants.ALARM_EVENT_RECORD_COMPLETED);
                    alarmEventRecordService.updateById(alarmEventRecordDto);
                }
            }
        }
        return workOrderDto.getId();
    }

    @Override
    public WorkOrderDto selectById(Long id) {
        WorkOrderEntity entity = workOrderDao.selectById(id);
        return paddingField(CopyUtils.copyObj(entity, WorkOrderDto.class));
    }

    @Override
    public List<WorkOrderDto> queryList(Map<String, Object> params) {
        List<WorkOrderEntity> list = workOrderDao.queryList(params);
        List<WorkOrderDto> result = CopyUtils.copyList(list, WorkOrderDto.class);
        result.forEach(this::paddingField);
        return result;
    }

    public WorkOrderDto paddingField(WorkOrderDto workOrderDto) {
        if (workOrderDto == null) {
            return null;
        }
        if (workOrderDto.getVillageId() != null) {
            VillageDto villageDto = villageService.selectCacheById(workOrderDto.getVillageId());
            if (villageDto != null) {
                workOrderDto.setVillageName(villageDto.getName());
            }
        }
        if (workOrderDto.getBuildingId() != null) {
            VillageBuildingDto villageBuildingDto = villageBuildingService.selectCacheById(workOrderDto.getBuildingId());
            if (villageBuildingDto != null) {
                workOrderDto.setBuildingName(villageBuildingDto.getName());
            }
        }
        if (workOrderDto.getFloorId() != null) {
            VillageFloorDto villageFloorDto = villageFloorService.selectCacheById(workOrderDto.getFloorId());
            if (villageFloorDto != null) {
                workOrderDto.setFloorName(villageFloorDto.getName());
            }
        }
        if (workOrderDto.getRoomId() != null) {
            VillageRoomDto villageRoomDto = villageRoomService.selectCacheById(workOrderDto.getRoomId());
            if (villageRoomDto != null) {
                workOrderDto.setRoomName(villageRoomDto.getName());
            }
        }
        return workOrderDto;
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return workOrderDao.queryTotal(params);
    }

    @Override
    public Long save(WorkOrderDto dto) {
        WorkOrderEntity entity = CopyUtils.copyObj(dto, WorkOrderEntity.class);
        entity.setId(Snowflake.nextId());
        workOrderDao.insert(entity);
        return entity.getId();
    }

    @Override
    public void updateById(WorkOrderDto dto) {
        WorkOrderEntity entity = CopyUtils.copyObj(dto, WorkOrderEntity.class);
        workOrderDao.updateById(entity);
    }


    @Override
    public void deleteById(Long id) {
        workOrderDao.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            deleteById(id);
        }
    }
}
